﻿using System.Web.UI.WebControls;
using System.Web.UI;
using System;
using System.ComponentModel;
using System.Web;


namespace ControlLibrary
{
    [ToolboxData("<{0}:EmbeddedUserControlLoader runat='server'></{0}:EmbeddedUserControlLoader>")]
    public class EmbeddedUserControlLoader : WebControl
    {
        public EmbeddedUserControlLoader()
        {
        }

        public EmbeddedUserControlLoader(string id, string assemblyName, string controlNamespace, string controlClassName)
            : this(assemblyName, controlNamespace, controlClassName)
        {
            this.ID = id;
        }

        public EmbeddedUserControlLoader(string assemblyName, string controlNamespace, string controlClassName)
        {
            this.AssemblyName = assemblyName;
            this.ControlNamespace = controlNamespace;
            this.ControlClassName = controlClassName;
        }

        # region VirtualPathProvider setup code

        static EmbeddedUserControlLoader()
        {
            if (!IsDesignMode)
            {
                System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProvider(
                    new AssemblyResourceProvider(ResourcePrefix));
            }
        }

        private static bool IsDesignMode
        {
            get { return HttpContext.Current == null; }
        }

        private static string mResourcePrefix = "EmbeddedWebResource";

        public static string ResourcePrefix
        {
            get { return mResourcePrefix; }

            set { mResourcePrefix = value; }
        }

        #endregion

        #region Toolbox properties

        private string mAssemblyName = "";

        [Bindable(true)]
        [Category("Behavior")]
        [Localizable(true)]
        public string AssemblyName
        {
            get { return mAssemblyName; }
            set { mAssemblyName = value; }
        }

        private string mControlNamespace = "";

        [Bindable(true)]
        [Category("Behavior")]
        [Localizable(true)]
        public string ControlNamespace
        {
            get { return mControlNamespace; }
            set { mControlNamespace = value; }
        }

        private string mControlClassName = "";

        [Bindable(true)]
        [Category("Behavior")]
        [Localizable(true)]
        public string ControlClassName
        {
            get { return mControlClassName; }
            set { mControlClassName = value; }
        }

        #endregion

        #region Private members

        private string Path
        {
            get
            {
                return String.Format("/{0}/{1}.dll/{2}.{3}.ascx", ResourcePrefix, AssemblyName, ControlNamespace,
                                     ControlClassName);
            }
        }

        private Control c;

        public IEmbeddedUserControl EmbeddedUserControl
        {
            get { return c as IEmbeddedUserControl; }
        }


        protected override void OnInit(EventArgs e)
        {
            //不能放在Repeater中
            c = Page.LoadControl(Path);
            OnControlLoaded();
            Controls.Add(c);
            base.OnInit(e);
        }

        protected override void OnLoad(EventArgs e)
        {
            //c = Page.LoadControl(Path);
            //Controls.Add(c);
            base.OnLoad(e);
        }

        protected override void RenderContents(HtmlTextWriter output)
        {
            if (IsDesignMode)
            {
                output.Write(Path);
                return;
            }
            base.RenderContents(output);
        }

        #endregion

        protected void OnControlLoaded()
        {
            EventHandler handler = ControlLoaded;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
        }

        public event EventHandler ControlLoaded;

        #region Helper members to access UserControl properties

        public void SetControlProperty(string propName, object value)
        {
            //c.GetType().GetProperty(propName).SetValue(c, value, null);
            this[propName] = value;
        }

        public object GetControlProperty(string propName)
        {
            //System.Reflection.PropertyInfo get = c.GetType().GetProperty(propName);

            //object returnValue = null;

            //returnValue = get.GetValue(c, null);
            //returnValue = FastMethodInvoker.FastMethodInvoker.GetMethodInvoker(get.GetGetMethod())(c, null);

            //return returnValue;

            return this[propName];
        }

        #endregion

        private System.Collections.Generic.IDictionary<string, System.Reflection.MethodInfo> MethodInfoCache =
            new System.Collections.Generic.Dictionary<string, System.Reflection.MethodInfo>();

        public object this[string propName]
        {
            get
            {
                string methodName = string.Format("GET_{0}", propName);

                System.Reflection.MethodInfo methodInfo = null;

                if (MethodInfoCache.ContainsKey(methodName) == false)
                {
                    Type type = c.GetType();
                    System.Reflection.PropertyInfo propInfo = type.GetProperty(propName);

                    if (propInfo != null && propInfo.CanRead)
                    {
                        methodInfo = propInfo.GetGetMethod();
                        MethodInfoCache.Add(methodName, methodInfo);
                    }
                }
                else
                {
                    methodInfo = MethodInfoCache[methodName];
                }

                object returnValue = null;
                if (methodInfo != null)
                {
                    object[] param = new object[] {null, null, null};
                    returnValue = FastMethodInvoker.FastMethodInvoker.GetMethodInvoker(methodInfo)(c, param);
                }

                return returnValue;
            }
            set
            {
                string methodName = string.Format("SET_{0}", propName);

                System.Reflection.MethodInfo methodInfo = null;
                if (MethodInfoCache.ContainsKey(methodName) == false)
                {
                    Type type = c.GetType();
                    System.Reflection.PropertyInfo propInfo = type.GetProperty(propName);
                    if (propInfo != null && propInfo.CanWrite)
                    {
                        methodInfo = propInfo.GetSetMethod();
                        MethodInfoCache.Add(methodName, methodInfo);
                    }
                }
                else
                {
                    methodInfo = MethodInfoCache[methodName];
                }

                if (methodInfo != null)
                {

                    object[] param = new object[] {value, c, null};

                    FastMethodInvoker.FastMethodInvoker.GetMethodInvoker(methodInfo)(c, param);
                }
            }
        }

        public object ControlMethod(string methodName, params object[] paramters)
        {
            System.Reflection.MethodInfo methodInfo = null;
            if (MethodInfoCache.ContainsKey(methodName) == false)
            {
                methodInfo = c.GetType().GetMethod(methodName);

                if (methodInfo != null)
                {
                    MethodInfoCache.Add(methodName, methodInfo);
                }
            }
            else
            {
                methodInfo = MethodInfoCache[methodName];
            }
            object returnValue = null;
            if (methodInfo != null)
            {
                try
                {
                    returnValue = FastMethodInvoker.FastMethodInvoker.GetMethodInvoker(methodInfo)(c, paramters);
                }
                catch (Exception ex)
                {
                    System.Text.StringBuilder message = new System.Text.StringBuilder();

                    message.Append(methodInfo.IsPublic ? "Public" : "Private");
                    message.AppendFormat(" {0} {1} ", methodInfo.ReturnType.Name, methodInfo.Name);
                    message.Append("(");
                    foreach (System.Reflection.ParameterInfo paramter in methodInfo.GetParameters())
                    {
                        message.AppendFormat(" {0} {1},", paramter.ParameterType.Name, paramter.Name);
                    }
                    message.Append(")");

                    string Message = string.Format("参数与方法签名不一致; {0}", message.ToString());
                    throw new Exception(Message.Replace(",)", ")"));
                }
            }
            return returnValue;
        }
    }

    [ToolboxData("<{0}:EmbeddedUserControlPlaceHolder runat='server'></{0}:EmbeddedUserControlPlaceHolder>")]
    public class EmbeddedUserControlPlaceHolder : PlaceHolder
    {
        #region Toolbox properties

        private EmbeddedUserControlLoader mLoader = null;

        public EmbeddedUserControlLoader Loader
        {
            get
            {
                if (mLoader == null)
                {
                    foreach (WebControl control in this.Controls)
                    {
                        if (control is EmbeddedUserControlLoader)
                        {
                            mLoader = control as EmbeddedUserControlLoader;
                            break;
                        }
                    }
                }
                return mLoader;
            }
        }

        #endregion
    }
}

